package org.opens.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.opens.entity.LotteryHistory;
import org.opens.entity.vo.LotteryHistoryModifyWave;
import org.opens.entity.vo.LotteryHistorySumDistribution;
import org.opens.entity.vo.LotteryHistoryTrend;
import org.opens.entity.vo.LotteryStandardDeviationWave;
import org.opens.factory.lottery.other.LotteryTypes;
import org.opens.service.LotteryHistoryService;
import org.opens.util.HttpCode;
import org.opens.util.HttpResult;
import org.opens.util.HttpSimpleResult;
import org.opens.util.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/api/lottery/history")
public class LotteryHistoryController {

    @Autowired
    private LotteryHistoryService lotteryHistoryService;

    @GetMapping(value = "/page")
    public PageResult<LotteryHistory> page(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "limit", defaultValue = "10") Integer limit,
            @RequestParam(value = "numOfPeriods", required = false) String numOfPeriods
    ) {
        PageResult<LotteryHistory> pageResult = new PageResult<>();
        LotteryHistory searchParam = new LotteryHistory();
        searchParam.setNumOfPeriods(StrUtil.trim(numOfPeriods));
        try {
            IPage<LotteryHistory> historyIPage = lotteryHistoryService.page(page, limit, searchParam);
            pageResult.setCode(HttpCode.LAYUI_PAGE_SUCCESS.value);
            pageResult.setMsg(HttpCode.LAYUI_PAGE_SUCCESS.message);
            pageResult.setCount(historyIPage.getTotal());
            pageResult.setData(historyIPage.getRecords());
        } catch (Exception e) {
            e.printStackTrace();
            pageResult.setCode(HttpCode.SERVER_ERROR.value);
            pageResult.setMsg(HttpCode.SERVER_ERROR.message);
        }
        return pageResult;
    }

    @PutMapping(value = "/sync/remote")
    public HttpSimpleResult syncRemote() {
        HttpSimpleResult result = new HttpSimpleResult();
        try {
            int modifyRowCount = lotteryHistoryService.syncLocalDbFromRemote(LotteryTypes.SSQ);
            result.setCode(HttpCode.SUCCESS.value);
            result.setMessage("本次同步" + modifyRowCount + "条数据");
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(HttpCode.SERVER_ERROR.value);
            result.setMessage(HttpCode.SERVER_ERROR.message);
        }
        return result;
    }

    @GetMapping(value = "/trend")
    public HttpResult trend(
            @RequestParam(value = "limit", defaultValue = "7") Integer limit
    ) {
        HttpResult result = new HttpResult();
        List<LotteryHistory> theLatest = null;
        try {
            theLatest = lotteryHistoryService.getTheLatest(LotteryTypes.SSQ, limit);
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(HttpCode.SERVER_ERROR.value);
            result.setMessage(HttpCode.SERVER_ERROR.message);
            return result;
        }
        if (CollectionUtil.isEmpty(theLatest)) {
            result.setCode(HttpCode.OTHER.value);
            result.setMessage("库中无数据, 无法分析, 请先同步远程");
            return result;
        }

        LotteryHistoryTrend build = LotteryHistoryTrend.build();

        for (LotteryHistory history : theLatest) {
            build.getRedNum1Arr().add(history.getRedNum1());
            build.getRedNum2Arr().add(history.getRedNum2());
            build.getRedNum3Arr().add(history.getRedNum3());
            build.getRedNum4Arr().add(history.getRedNum4());
            build.getRedNum5Arr().add(history.getRedNum5());
            build.getRedNum6Arr().add(history.getRedNum6());
            build.getBlueNumArr().add(history.getBlueNum());
            build.getXAxisData().add(history.getNumOfPeriods());
        }
        // 反序操作, 使echars中按期数从左到右排列
        build.reverse();
        result.setCode(HttpCode.SUCCESS.value);
        result.setData(build);
        return result;
    }

    @GetMapping(value = "/modify/wave")
    public HttpResult getModifyWave(
            @RequestParam(value = "limit", defaultValue = "7") Integer limit
    ) {
        HttpResult result = new HttpResult();
        List<LotteryHistoryModifyWave> modifyWaves = null;
        try {
            modifyWaves = lotteryHistoryService.getModifyWave(LotteryTypes.SSQ, limit);
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(HttpCode.SERVER_ERROR.value);
            result.setMessage(HttpCode.SERVER_ERROR.message);
            return result;
        }
        if (CollectionUtil.isEmpty(modifyWaves)) {
            result.setCode(HttpCode.OTHER.value);
            result.setMessage("库中无数据, 无法分析, 请先同步远程");
            return result;
        }

        LotteryHistoryTrend build = LotteryHistoryTrend.build();

        for (LotteryHistoryModifyWave modifyWave : modifyWaves) {
            build.getRedNum1Arr().add(modifyWave.getRedNum1());
            build.getRedNum2Arr().add(modifyWave.getRedNum2());
            build.getRedNum3Arr().add(modifyWave.getRedNum3());
            build.getRedNum4Arr().add(modifyWave.getRedNum4());
            build.getRedNum5Arr().add(modifyWave.getRedNum5());
            build.getRedNum6Arr().add(modifyWave.getRedNum6());
            build.getBlueNumArr().add(modifyWave.getBlueNum());
            build.getXAxisData().add(modifyWave.getNumOfPeriods());

            build.getRedNum1ModifyArr().add(modifyWave.getProRedNum1Modify());
            build.getRedNum2ModifyArr().add(modifyWave.getProRedNum2Modify());
            build.getRedNum3ModifyArr().add(modifyWave.getProRedNum3Modify());
            build.getRedNum4ModifyArr().add(modifyWave.getProRedNum4Modify());
            build.getRedNum5ModifyArr().add(modifyWave.getProRedNum5Modify());
            build.getRedNum6ModifyArr().add(modifyWave.getProRedNum6Modify());
            build.getBlueNumModifyArr().add(modifyWave.getProBlueNumModify());
        }
        // 反序操作, 使echars中按期数从左到右排列
        build.reverse();
        result.setCode(HttpCode.SUCCESS.value);
        result.setData(build);
        return result;
    }

    @GetMapping(value = "/sum/distribution")
    public HttpResult getSumDistribution() {
        HttpResult result = new HttpResult();
        List<LotteryHistorySumDistribution> ssqLotteryHistorySumDistribution = null;
        try {
            ssqLotteryHistorySumDistribution = lotteryHistoryService.getSSQLotteryHistorySumDistribution();
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(HttpCode.SERVER_ERROR.value);
            result.setMessage(HttpCode.SERVER_ERROR.message);
            return result;
        }

        if (CollectionUtil.isEmpty(ssqLotteryHistorySumDistribution)) {
            result.setCode(HttpCode.OTHER.value);
            result.setMessage("库中无数据, 无法分析, 请先同步远程");
            return result;
        }

        Map<String, Object> mapTemp = new HashMap<>();
        mapTemp.put("xData", ssqLotteryHistorySumDistribution.stream().map(LotteryHistorySumDistribution::getSumNumber).collect(Collectors.toList()));
        mapTemp.put("yData", ssqLotteryHistorySumDistribution.stream().map(LotteryHistorySumDistribution::getCount).collect(Collectors.toList()));

        result.setCode(HttpCode.SUCCESS.value);
        result.setData(mapTemp);
        return result;
    }

    @GetMapping(value = "/standard/deviation/wave")
    public HttpResult getStandardDeviationWave(
            @RequestParam(value = "limit", defaultValue = "7") Integer limit
    ) {
        HttpResult result = new HttpResult();
        List<LotteryHistory> theLatest = null;
        try {
            theLatest = lotteryHistoryService.getTheLatest(LotteryTypes.SSQ, limit);
            Collections.reverse(theLatest);
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(HttpCode.SERVER_ERROR.value);
            result.setMessage(HttpCode.SERVER_ERROR.message);
            return result;
        }

        if (CollectionUtil.isEmpty(theLatest)) {
            result.setCode(HttpCode.OTHER.value);
            result.setMessage("库中无数据, 无法分析, 请先同步远程");
            return result;
        }

        LotteryStandardDeviationWave sdWave = LotteryStandardDeviationWave.build();

        for (int i = 0; i < theLatest.size(); i++) {
            LotteryHistory startElement = theLatest.get(0);
            LotteryHistory temp = theLatest.get(i);
            if (i == 0) {
                sdWave.getXData().add(temp.getNumOfPeriods());
                sdWave.getRedNum1Sd().add(0D);
                sdWave.getRedNum2Sd().add(0D);
                sdWave.getRedNum3Sd().add(0D);
                sdWave.getRedNum4Sd().add(0D);
                sdWave.getRedNum5Sd().add(0D);
                sdWave.getRedNum6Sd().add(0D);
                sdWave.getBlueNumSd().add(0D);
                continue;
            }

            // 求出计算标准差待用平均值
            double redNum1Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum1).average().getAsDouble();
            double redNum2Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum2).average().getAsDouble();
            double redNum3Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum3).average().getAsDouble();
            double redNum4Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum4).average().getAsDouble();
            double redNum5Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum5).average().getAsDouble();
            double redNum6Avg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getRedNum6).average().getAsDouble();
            double blueNumAvg = theLatest.stream().limit(i + 1).mapToInt(LotteryHistory::getBlueNum).average().getAsDouble();

            Double redNum1SdValue = 0D;
            Double redNum2SdValue = 0D;
            Double redNum3SdValue = 0D;
            Double redNum4SdValue = 0D;
            Double redNum5SdValue = 0D;
            Double redNum6SdValue = 0D;
            Double blueNumSdValue = 0D;
            // 求标准差过程1
            for (int j = 0; j <= i; j++) {
                LotteryHistory temp2 = theLatest.get(j);
                double redNum1SdValueTemp = Math.pow(temp2.getRedNum1() - redNum1Avg, 2) / (i + 1);
                double redNum2SdValueTemp = Math.pow(temp2.getRedNum2() - redNum2Avg, 2) / (i + 1);
                double redNum3SdValueTemp = Math.pow(temp2.getRedNum3() - redNum3Avg, 2) / (i + 1);
                double redNum4SdValueTemp = Math.pow(temp2.getRedNum4() - redNum4Avg, 2) / (i + 1);
                double redNum5SdValueTemp = Math.pow(temp2.getRedNum5() - redNum5Avg, 2) / (i + 1);
                double redNum6SdValueTemp = Math.pow(temp2.getRedNum6() - redNum6Avg, 2) / (i + 1);
                double blueNumSdValueTemp = Math.pow(temp2.getBlueNum() - blueNumAvg, 2) / (i + 1);
                redNum1SdValue += redNum1SdValueTemp;
                redNum2SdValue += redNum2SdValueTemp;
                redNum3SdValue += redNum3SdValueTemp;
                redNum4SdValue += redNum4SdValueTemp;
                redNum5SdValue += redNum5SdValueTemp;
                redNum6SdValue += redNum6SdValueTemp;
                blueNumSdValue += blueNumSdValueTemp;
            }
            // 求出算数平方根来算出真正的标准差
            sdWave.getXData().add(startElement.getNumOfPeriods() + "~" + temp.getNumOfPeriods());
            sdWave.getRedNum1Sd().add(Math.sqrt(redNum1SdValue));
            sdWave.getRedNum2Sd().add(Math.sqrt(redNum2SdValue));
            sdWave.getRedNum3Sd().add(Math.sqrt(redNum3SdValue));
            sdWave.getRedNum4Sd().add(Math.sqrt(redNum4SdValue));
            sdWave.getRedNum5Sd().add(Math.sqrt(redNum5SdValue));
            sdWave.getRedNum6Sd().add(Math.sqrt(redNum6SdValue));
            sdWave.getBlueNumSd().add(Math.sqrt(blueNumSdValue));
        }

        result.setCode(HttpCode.SUCCESS.value);
        result.setData(sdWave);
        return result;
    }

}
